#include "unp.h"

/*
 * int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask);
 * struct pollfd {
               int   fd;         
               short events;     
               short revents;    
           };
 * */

#define MAXFDS 1024

int main() {
	int serv_fd, maxi;
	struct pollfd fds[MAXFDS];
	char buf[MAXLINE], ip[16];
	if((serv_fd = socket(AF_INET, SOCK_STREAM,0)) == -1 ) {
		err_exit("call socket error.");
	}
	struct sockaddr_in serv_addr,client_addr;
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(9987);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if(bind(serv_fd,(struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0) {
		err_exit("bind serv addr error.");
	}
	if(listen(serv_fd, MAXFDS-1) != 0) {
		err_exit("listen serv fd error");
	}
	fds[0].fd = serv_fd;
	fds[0].events = POLLRDNORM;
	for(int i = 1; i < MAXFDS; ++i) {
		fds[i].fd = -1;
		fds[i].events = 0;
		fds[i].revents = 0;
	}
	maxi = 1;
	for(;;) {
		int nready = poll(fds, maxi, 10); // timeout=10ms
		if(nready == 0) continue;
		if(nready == -1) {
			if(errno == EINTR) continue;
			else err_exit("poll error.");
		}
		if(fds[0].revents & POLLRDNORM) {
			socklen_t cliaddr_len = sizeof(client_addr);
			int client_fd = accept(serv_fd,(struct sockaddr*)&client_addr,&cliaddr_len);
			if(client_fd < 0) {
				err_sys("accept new connection error.");
			} else {
				printf("new connection:[%s:%u]\n", inet_ntop(AF_INET,&client_addr.sin_addr, ip, 16), ntohs(client_addr.sin_port));
				int i;
				for(i = 1; i < MAXFDS; ++i) {
					if(fds[i].fd == -1) {
						fds[i].fd = client_fd;
						fds[i].events = POLLRDNORM;
						fds[i].revents = 0;
						break;
					}
				}
				if(maxi < i + 1) maxi = i + 1;
			}
			if(--nready == 0) continue; // no other ready fd.
		}
		for(int i = 1; i < maxi; ++i) {
			if(fds[i].fd == -1) continue;
			if(! (fds[i].revents & (POLLRDNORM|POLLERR))) continue;
			int n = 0;
			if((n = read(fds[i].fd, buf, MAXLINE)) > 0 ) {
				Write(fds[i].fd, buf, n);
			} else {
				if(errno == EINTR) continue;
				socklen_t cliaddr_len = sizeof(client_addr);
				if(getpeername(fds[i].fd, (struct sockaddr*)&client_addr, &cliaddr_len) == -1) { // 对端发送RST包，getpeername会报错
					err_sys("get client sock name error");
				}
				else if(n == 0) {
					printf("client[%s:%u] close\n",  inet_ntop(AF_INET, &client_addr.sin_addr, ip, 16), ntohs(client_addr.sin_port));
				} else {
					err_sys("client[%s:%u] reset connection\n",  inet_ntop(AF_INET, &client_addr.sin_addr, ip, 16), ntohs(client_addr.sin_port));
				}
				close(fds[i].fd);
				fds[i].fd = -1;
			}
		}
	}
	return 0;
}
